import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class TcpEchoServer {
    private ServerSocket serverSocket = null;

    //创建实例
    public TcpEchoServer(int port) throws IOException {
        serverSocket = new ServerSocket(port);
    }

    public void start() throws IOException {
        System.out.println("启动服务器");
        while (true){
            //使用这个对象与具体的客户端进行交流
            Socket clientSocket = serverSocket.accept();
            processConnection(clientSocket);
        }
    }

    //使用这个方法来处理一个连接
    //这一个连接对应到一个客户端,但是这里可能会涉及到多次交互
    private void processConnection(Socket clientSocket) throws IOException {
        System.out.printf("[%s:%d] 客户端上线!\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());
        //基于上述Socket对象和客户端进行通信
        try (InputStream inputStream = clientSocket.getInputStream();
                OutputStream outputStream = clientSocket.getOutputStream()){
            //由于要对多个请求作出相应,所以要用循环来进行
            while (true) {
                // 1.读取请求
                Scanner scanner = new Scanner(inputStream);
                if(!scanner.hasNext()) {
                    //没有下一个数据了,说明读完了(客户端关闭了连接)
                    System.out.printf("[%s:%d] 客户端下线\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());
                    break;
                }
                //注意!此处使用next是一直读到 换行符/空格/其他空白符结束,但是最终返回的结果不包括上述"特殊"空白符
                String request = scanner.next();
                // 2.根据请求构造响应
                String response = process(request);
                // 3.返回响应结果
                //OutputString没有write string这个功能,可以把String里的字节数组拿出来进行写入;也可以用字符流来换一下
                PrintWriter printWriter = new PrintWriter(outputStream);
                printWriter.println(request);
                //flush用来刷新缓冲区,保证当前写入的数据发出去的可靠性
                printWriter.flush();

                System.out.printf("[%s:%d] req: %s; resp: %s \n", clientSocket.getInetAddress().toString(), clientSocket.getPort(),
                                                                    request, response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //把释放资源放在finally里,保证一定能执行到
            try {
                clientSocket.close();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }

    //根据请求构造响应
    public String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        TcpEchoServer server = new TcpEchoServer(9090);
        server.start(); //但是当前只能处理一个客户端
    }
}
